page.tsx 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import Link from 'next/link';
  2. import { ArrowRight, BookOpen, Heart } from 'lucide-react';
  3. import { GitHubIcon, TelegramIcon } from '@/components/icons';
  4. import { Logo } from '@/components/logo';
  5. import { Features } from '@/components/home/features';
  6. import { GitHubStatsRow } from '@/components/home/github-stats';
  7. import { InstallCommand } from '@/components/home/install-command';
  8. import { getGitHubStats } from '@/lib/github-stats';
  9. import { i18n } from '@/lib/i18n';
  10. import { appName, productRepoUrl, deepWikiUrl, telegramChannelUrl, donateUrl } from '@/lib/shared';
  11. import { getSiteMessages, type SiteMessages } from '@/lib/site-i18n';
  12. export function generateStaticParams() {
  13. return i18n.languages.map((lang) => ({ lang }));
  14. }
  15. const INSTALL_COMMAND =
  16. 'bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)';
  17. export default async function HomePage({ params }: PageProps<'/[lang]'>) {
  18. const { lang } = await params;
  19. const prefix = lang === 'en' ? '' : `/${lang}`;
  20. const m = getSiteMessages(lang);
  21. const stats = await getGitHubStats();
  22. return (
  23. <main className="flex flex-1 flex-col">
  24. {/* Hero */}
  25. <section className="relative overflow-hidden border-b">
  26. <div
  27. className="pointer-events-none absolute inset-x-0 -top-40 h-80 bg-gradient-to-b from-brand/15 to-transparent blur-3xl"
  28. aria-hidden
  29. />
  30. <div className="mx-auto flex w-full max-w-5xl flex-col items-center px-4 py-20 text-center sm:py-28">
  31. <Logo className="h-20 drop-shadow-sm" />
  32. <h1 className="mt-6 text-4xl font-bold tracking-tight sm:text-6xl">
  33. <span className="bg-gradient-to-r from-cyan-500 to-sky-600 bg-clip-text text-transparent dark:from-cyan-300 dark:to-sky-400">
  34. {appName}
  35. </span>
  36. </h1>
  37. <p className="mt-4 max-w-2xl text-lg text-fd-muted-foreground sm:text-xl">{m.tagline}</p>
  38. <div className="mt-8 flex flex-col items-center gap-3 sm:flex-row">
  39. <Link
  40. href={`${prefix}/docs`}
  41. className="inline-flex items-center gap-2 rounded-xl bg-fd-primary px-5 py-3 font-medium text-fd-primary-foreground transition-opacity hover:opacity-90"
  42. >
  43. {m.getStarted}
  44. <ArrowRight className="size-4 rtl:rotate-180" aria-hidden />
  45. </Link>
  46. <a
  47. href={productRepoUrl}
  48. target="_blank"
  49. rel="noreferrer noopener"
  50. className="inline-flex items-center gap-2 rounded-xl border px-5 py-3 font-medium transition-colors hover:bg-fd-accent hover:text-fd-accent-foreground"
  51. >
  52. <GitHubIcon className="size-4" />
  53. {m.viewOnGitHub}
  54. </a>
  55. </div>
  56. <InstallCommand
  57. command={INSTALL_COMMAND}
  58. copyLabel={m.copyCommand}
  59. copiedLabel={m.copied}
  60. className="mt-8 w-full max-w-2xl"
  61. />
  62. {/* Build-time stats as the initial render; refreshed live on the client. */}
  63. <GitHubStatsRow
  64. initial={stats}
  65. labels={{ stars: m.stars, forks: m.forks, latest: m.latest }}
  66. />
  67. </div>
  68. </section>
  69. <Features heading={m.featuresHeading} subtitle={m.featuresSubtitle} items={m.features} />
  70. <Footer prefix={prefix} m={m} />
  71. </main>
  72. );
  73. }
  74. function Footer({ prefix, m }: { prefix: string; m: SiteMessages }) {
  75. return (
  76. <footer className="border-t">
  77. <div className="mx-auto flex w-full max-w-6xl flex-col items-center justify-between gap-4 px-4 py-8 text-sm text-fd-muted-foreground sm:flex-row">
  78. <div className="inline-flex items-center gap-2">
  79. <Logo className="h-6" />
  80. <span>
  81. {appName} — {m.licenseBefore}
  82. <a
  83. href={`${productRepoUrl}/blob/main/LICENSE`}
  84. className="underline hover:text-fd-foreground"
  85. >
  86. GPL-3.0
  87. </a>
  88. {m.licenseAfter}
  89. </span>
  90. </div>
  91. <nav className="flex items-center gap-4">
  92. <Link href={`${prefix}/docs`} className="hover:text-fd-foreground">
  93. {m.docs}
  94. </Link>
  95. <a
  96. href={productRepoUrl}
  97. className="inline-flex items-center gap-1.5 hover:text-fd-foreground"
  98. >
  99. <GitHubIcon className="size-4" />
  100. GitHub
  101. </a>
  102. <a
  103. href={deepWikiUrl}
  104. target="_blank"
  105. rel="noreferrer noopener"
  106. className="inline-flex items-center gap-1.5 hover:text-fd-foreground"
  107. >
  108. <BookOpen className="size-4" />
  109. DeepWiki
  110. </a>
  111. <a
  112. href={telegramChannelUrl}
  113. target="_blank"
  114. rel="noreferrer noopener"
  115. className="inline-flex items-center gap-1.5 hover:text-fd-foreground"
  116. >
  117. <TelegramIcon className="size-4" />
  118. Telegram
  119. </a>
  120. <a
  121. href={donateUrl}
  122. target="_blank"
  123. rel="noreferrer noopener"
  124. className="inline-flex items-center gap-1.5 hover:text-fd-foreground"
  125. >
  126. <Heart className="size-4" />
  127. {m.donate}
  128. </a>
  129. </nav>
  130. </div>
  131. </footer>
  132. );
  133. }